package edu.vcu.csl.ess;

import java.util.ArrayList;

import edu.vcu.csl.ess.RawModel.*;


class DependencyGen {
	public static void calculateReactionDeltas(RawModel model) {

		// For each reaction, compute the species delta = products - reactants.
		for (Reaction reaction : model.reactions) {

			// Subtract the reactants from the delta.
			for (ReactionElement reactant : reaction.reactants) {
				ReactionElement temp = new ReactionElement();
				temp.species         = reactant.species;
				temp.coefficient     = -reactant.coefficient;
				reaction.delta.add(temp);
			}

			// Add the products to the delta.
			for (ReactionElement product : reaction.products) {
				boolean found = false;
				for (ReactionElement delta : reaction.delta) {
					if (delta.species.compareTo(product.species) == 0) {
						found = true;
						delta.coefficient += product.coefficient;
						break;
					}
				}
				if (!found) {
					ReactionElement temp = new ReactionElement();
					temp.species         = product.species;
					temp.coefficient     = product.coefficient;
					reaction.delta.add(temp);		    
				}
			}	    

			// Eliminate all zero coefficient items.
			for (ReactionElement delta : reaction.delta) {
				if (delta.coefficient == 0) {
					reaction.delta.remove(delta);
				}
			}
		}
	}

	public static void calculateModelDependencies(RawModel model) {

		// For each reaction, determine the reactions and triggers 
		// that depend on the execution of reaction.
		for (Reaction reaction : model.reactions) {

			// Look for dependent reactions
			for (Reaction reaction2 : model.reactions) {
				boolean affects = false;
				for (ReactionElement element : reaction.delta) {
					for(ReactionElement element2 : reaction2.reactants) {
						if (element.species.compareTo(element2.species) == 0) {
							affects = true;
							break;
						}
					}
				}
				if (affects) 
					reaction.affectedReactionList.add(reaction2);
			}

			// Look for dependent triggers
			for (Trigger trigger : model.triggers) {
				ArrayList<String> conditionNames = 
					JavaCodeParser.getNamesFromCode(trigger.condition);
				boolean affects = false;
				for (ReactionElement delta : reaction.delta) {
					for (String conditionName : conditionNames) {
						if (conditionName.compareTo(delta.species) == 0) {
							affects = true;
							break;
						}
					}
				}
				if (affects) 
					reaction.affectedTriggerList.add(trigger);
			}	    
		}

		// For each event, determine the reactions and triggers
		// that depend on that event.
		for (Event event : model.events) {
			ArrayList<String> actionNames = 
				JavaCodeParser.getNamesFromCode(event.action);

			for (Reaction reaction : model.reactions) {
				boolean affects = false;
				for (String actionName : actionNames) {
					for (ReactionElement reactant : reaction.reactants) {
						if (reactant.species.compareTo(actionName) == 0) {
							affects = true;
							break;
						}
					}
					if (actionName.compareTo(reaction.name) == 0) {
						affects = true;
					}
				}
				if (affects) 
					event.affectedReactionList.add(reaction);
			}

			for (Trigger trigger : model.triggers) {
				ArrayList<String> conditionNames = 
					JavaCodeParser.getNamesFromCode(trigger.condition);
				boolean affects = false;
				for (String actionName : actionNames) {
					for (String conditionName : conditionNames) {
						if (actionName.compareTo(conditionName) == 0) {
							affects = true;
							break;
						}
					}
					if (actionName.compareTo(trigger.name) == 0) {
						affects = true;
						break;
					}
				}
				if (affects) 
					event.affectedTriggerList.add(trigger);
			}
		}

		// For each periodic, determine the reactions and triggers
		// that depend on that event.
		for (Periodic event : model.periodics) {
			ArrayList<String> actionNames = 
				JavaCodeParser.getNamesFromCode(event.action);

			for (Reaction reaction : model.reactions) {
				boolean affects = false;
				for (String actionName : actionNames) {
					for (ReactionElement reactant : reaction.reactants) {
						if (reactant.species.compareTo(actionName) == 0) {
							affects = true;
							break;
						}
					}
					if (actionName.compareTo(reaction.name) == 0) {
						affects = true;
					}
				}
				if (affects) 
					event.affectedReactionList.add(reaction);
			}

			for (Trigger trigger : model.triggers) {
				ArrayList<String> conditionNames = 
					JavaCodeParser.getNamesFromCode(trigger.condition);
				boolean affects = false;
				for (String actionName : actionNames) {
					for (String conditionName : conditionNames) {
						if (actionName.compareTo(conditionName) == 0) {
							affects = true;
							break;
						}
					}
					if (actionName.compareTo(trigger.name) == 0) {
						affects = true;
						break;
					}
				}
				if (affects) 
					event.affectedTriggerList.add(trigger);
			}
		}	

		// For each trigger, determine the reactions and triggers
		// that depend on that event.
		for (Trigger trigger : model.triggers) {
			ArrayList<String> actionNames = 
				JavaCodeParser.getNamesFromCode(trigger.action);

			for (Reaction reaction : model.reactions) {
				boolean affects = false;
				for (String actionName : actionNames) {
					for (ReactionElement reactant : reaction.reactants) {
						if (reactant.species.compareTo(actionName) == 0) {
							affects = true;
							break;
						}
					}
					if (actionName.compareTo(reaction.name) == 0) {
						affects = true;
					}
				}
				if (affects) 
					trigger.affectedReactionList.add(reaction);
			}

			for (Trigger trigger2 : model.triggers) {
				ArrayList<String> conditionNames = 
					JavaCodeParser.getNamesFromCode(trigger2.condition);
				boolean affects = false;
				for (String actionName : actionNames) {
					for (String conditionName : conditionNames) {
						if (actionName.compareTo(conditionName) == 0) {
							affects = true;
							break;
						}
					}
					if (actionName.compareTo(trigger2.name) == 0) {
						affects = true;
						break;
					}
				}
				if (affects) 
					trigger.affectedTriggerList.add(trigger2);
			}
		}	
	}
}